
// Declare that there is a global property named "Headers" - this might not be present at runtime
declare const Headers: any;


export function normalizeName(name: any): string {
    if (typeof name !== "string") {
        name = String(name)
    }
    if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
        throw new TypeError("Invalid character in header field name")
    }
    return name.toLowerCase()
}


export function normalizeValue(value: any): string {
    if (typeof value !== "string") {
        value = String(value)
    }
    return value
}

export class Metadata {

    headersMap: { [key: string]: string[] };


    constructor(init: string) {
        this.headersMap = {};
        this.appendFromString(init);
    }

    appendFromString(str: string): void {
        const pairs = str.split("\r\n");
        for (let i = 0; i < pairs.length; i++) {
            const p = pairs[i];
            const index = p.indexOf(":");
            if (index > 0) {
                const key = p.substring(0, index).trim();
                const value = p.substring(index + 1).trim();
                this.append(key, value);
            }
        }
    }

    append(key: string, value: string | string[]): void {
        const normalizedKey = normalizeName(key);
        if (!Array.isArray(this.headersMap[normalizedKey])) {
            this.headersMap[normalizedKey] = [];
        }
        if (Array.isArray(value)) {
            value.forEach(arrayValue => {
                this.headersMap[normalizedKey].push(normalizeValue(arrayValue));
            });
        } else {
            this.headersMap[normalizedKey].push(normalizeValue(value));
        }
    }

    forEach(callback: (key: string, values: string[]) => void): void {
        Object.getOwnPropertyNames(this.headersMap)
            .forEach(key => {
                callback(key, this.headersMap[key]);
            }, this);
    }

    toHeaders(): Headers {
        if (typeof Headers !== "undefined") {
            const headers = new Headers();
            this.forEach((key, values) => {
                values.forEach(value => {
                    headers.append(key, value);
                });
            });
            return headers;
        } else {
            throw new Error("Headers class is not defined");
        }
    }

}